package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.aliyun.iot20180120.Client;
import com.aliyun.iot20180120.models.*;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;
import com.zzyl.base.IBasicEnum;
import com.zzyl.base.PageResponse;
import com.zzyl.base.ResponseResult;
import com.zzyl.constant.CacheConstants;
import com.zzyl.dto.DeviceDto;
import com.zzyl.dto.DevicePageQueryDto;
import com.zzyl.entity.Device;
import com.zzyl.enums.BasicEnum;
import com.zzyl.enums.DeviceLocationTypeEnum;
import com.zzyl.enums.DevicePhysicalLocationTypeEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeviceMapper;
import com.zzyl.properties.AliIoTConfigProperties;
import com.zzyl.service.DeviceService;
import com.zzyl.vo.AlertDataVo;
import com.zzyl.vo.DeviceVo;
import com.zzyl.vo.ProductVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

/**
 * @Description DeviceServiceImpl
 * @Author zhengyuan&junjun
 * @Date 2024-10-30
 */
@Service
@Slf4j
public class DeviceServiceImpl implements DeviceService {
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private Client client;
    @Autowired
    private AliIoTConfigProperties aliIoTConfigProperties;
    @Autowired
    private DeviceMapper deviceMapper;
    @Override
    public void syncProductList() {
        //调用查询IOT所有产品列表：QueryProductList
        //1.构建查询产品列表请求对象
        QueryProductListRequest request = new QueryProductListRequest();
        request.setPageSize(200);
        request.setCurrentPage(1);
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());

        //2.client执行查询产品列表接口调用，返回响应对象
        QueryProductListResponse response = null;
        try {
            response = client.queryProductList(request);
        } catch (Exception e) {
            e.printStackTrace();
            //3.处理远程接口调用异常，结束应用程序
            throw new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);


        }

        //4.获取响应体success判断是否调用成功，失败抛出异常，结束程序
        if (!response.getBody().getSuccess()){
            log.error("同步IOT所有产品列表数据发生错误：{}",response.getBody().getErrorMessage());
            throw  new BaseException(BasicEnum.IOT_LIST_PRODUCT_ERROR);
        }

        //5.获取响应体 body.data.list.productInfo集合
        List<QueryProductListResponseBody.QueryProductListResponseBodyDataListProductInfo>
                productInfo = response.getBody().getData().getList().getProductInfo();
        //6.将productInfo集合转换为List<ProductVo>
        List<ProductVo> productVos = BeanUtil.copyToList(productInfo, ProductVo.class);


        //7.写入缓存
        redisTemplate.opsForValue().set(CacheConstants.All_PRODUCT_KEY, JSONUtil.toJsonStr(productVos));
    }

    @Override
    public List<ProductVo> allProduct() {

        String json = redisTemplate.opsForValue().get(CacheConstants.All_PRODUCT_KEY);
        if (StrUtil.isNotEmpty(json)){
            return  JSONUtil.toList(json,ProductVo.class);

        }

        return null;
    }
    /**
     * 分页查询设备列表
     *
     *
     * ***/
    @Override
    public PageResponse<DeviceVo> pageQueryDevice(DevicePageQueryDto devicePageQueryDto) {
       PageHelper.startPage(devicePageQueryDto.getPageNum(),devicePageQueryDto.getPageSize());
        Page<DeviceVo> deviceVos = deviceMapper.selectByPage(devicePageQueryDto);
        return PageResponse.of(deviceVos,DeviceVo.class);
    }

    /**
     * 查询设备详情数据
     *
     *
     * **/
    @Override
    public DeviceVo queryDeviceDetail(QueryDeviceDetailRequest request) {

       //1.调用mapper调用根据iotId查询数据库设备详情数据DeviceVo
       DeviceVo deviceVo =  deviceMapper.findByIotId(request.getIotId());
       if (deviceVo == null){
           throw  new RuntimeException("不存在当前设备");
       }
       //2.远程调用IOT查询设备详情数据接口QueryDeviceDetailRequest
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDeviceDetailResponse response = null;
        try {
          response =  client.queryDeviceDetail(request);
        } catch (Exception e) {
           log.error("获取IOT远程设备详情数据失败，失败原因：{}",e.getMessage());
        }
        if (!response.getBody().getSuccess()){
            log.error("获取IOT远程设备详情数据失败，失败原因：{}",response.getBody().getErrorMessage());
        }
        //3.将从IOT获取的详情数据封装给DeviceVo
        if (response.getBody().getSuccess()){
            QueryDeviceDetailResponseBody.QueryDeviceDetailResponseBodyData
                    data = response.getBody().getData();
            BeanUtil.copyProperties(data,deviceVo);
        }


        return deviceVo;
    }

    @Scheduled(cron="0 0 1 * * ?")
    public  void  executeTask(){
        log.info("定时任务正在执行---------------------------");
        deviceMapper.updateStatus(LocalDateTime.now());

    }


    /**
     * 注册设备
     * **/

    @Override
    public void registerDevice(DeviceDto deviceDto) {


        //1.查询数据库注册的设备英文名是否重复
        //根据设备英文名查询设备对应数量
       Long count = deviceMapper.findCountByDeviceName(deviceDto.getDeviceName());

       //数量大于0，说明已存在，抛出异常结束程序
         if (count > 0){
             throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
         }

        //2.远程调用IOT注册设备RegisterDevice接口，并且获取生成的设备id
        //从deviceDto中获取注册设备请求对象
        RegisterDeviceRequest request = deviceDto.getRegisterDeviceRequest();
        //注册设备请求对象封装IotInstanceId属性
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //远程调用注册设备接口获取返回RegisterDeviceResponse对象
        RegisterDeviceResponse response = null;
        try {
            response = client.registerDevice(request);
        } catch (Exception e) {
            //捕获远程调用可能发生的异常,抛出友好提示异常
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //获取RegisterDeviceResponse对象返回数据success判断是否调用成功，失败抛出友好提示异常
        if (!response.getBody().getSuccess()){
            log.error("注册设备失败，失败原因:{}",response.getBody().getErrorMessage());
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //接口调用成功，获取生成的设备id（响应体data.IotId），封装到deviceDto
        deviceDto.setIotId(response.getBody().getData().getIotId());

        //3.deviceDto转换为device对象
        Device device = BeanUtil.toBean(deviceDto, Device.class);
        //4.补全产品的名字，远程调用查询产品QueryProduct接口
        QueryProductRequest queryProductRequest = new QueryProductRequest();
        //构建查询产品请求对象，封装属性ProductKey和IotInstanceId
        queryProductRequest.setProductKey(device.getProductKey());
        queryProductRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        //远程调用注册设备接口获取返回QueryProductResponse对象
        QueryProductResponse queryProductResponse;
        try {
            queryProductResponse =  client.queryProduct(queryProductRequest);
        } catch (Exception e) {
            //捕获远程调用可能发生的异常,抛出友好提示异常
            log.error("注册设备失败，失败原因:{}","查询产品名字失败");
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }


        //获取QueryProductResponse对象返回数据success判断是否调用成功，失败抛出友好提示异常
        if (!queryProductResponse.getBody().getSuccess()){
            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);
        }
        //接口调用成功，获取产品名字（响应体data.ProductName），封装到device
        device.setProductName(queryProductResponse.getBody().getData().getProductName());

        //5.判断设备位置绑定类型是否为随身设备，如果是设置物理班绑定类型（physicalLocationType）为-1
         if (DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal().equals(device.getLocationType())){

             device.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
         }
        //6.将设备保存到数据库
        //补全是否包含门禁，默认设置为0
        device.setHaveEntranceGuard(0);

        try {
            //调用mapper保存
            deviceMapper.insertSelective(device);

        } catch (Exception e) {
            //捕获异常，远程调用删除IOT设备接口（DeleteDevice）
            //构建查删除IOT设备请求对象，封装属性IotInstanceId和IotId
            DeleteDeviceRequest deleteDeviceRequest = new DeleteDeviceRequest();
            deleteDeviceRequest.setIotId(device.getIotId());
            deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
            //远程调用删除设备接口
            DeleteDeviceResponse deleteDeviceResponse = null;
            try {
                deleteDeviceResponse =   client.deleteDevice(deleteDeviceRequest);
            } catch (Exception ex) {
                //捕获删除设备远程接口调用发生异常（如果其企业中删除失败，会记录日志，通知管理员（邮件或手机短信））
                 log.error("注册设备失败，失败原因:{}","删除iot的设备失败");

            }
            //获取QDeleteDeviceResponse对象返回数据success判断是否调用成功，失败抛出友好提示异常（如果其企业中删除失败，会记录日志，通知管理员（邮件或手机短信））
            if (!deleteDeviceResponse.getBody().getSuccess()){

                log.error("注册设备失败，失败原因:{}","删除iot的设备失败");
            }
            //抛出异常结束，提示友好信息

            throw new BaseException(BasicEnum.IOT_QUERY_DEVICE_ERROR);



        }



    }
    /**
     *
     * 查询指定设备的物模运行状态
     *
     * **/

    @Override
    public ResponseResult queryDevicePropertyStatus(QueryDevicePropertyStatusRequest request) {
         //1.获取设备id
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryDevicePropertyStatusResponse response;
        try {
            response =  client.queryDevicePropertyStatus(request);
        } catch (Exception e) {
           throw  new BaseException(BasicEnum. IOT_QUERY_DEVICE_PROPERTY_STATUS_ERROR);
        }
        return ResponseResult.success(response.getBody().getData());
    }
     /**
      *
      * 查看指定产品的已发布物模型中的功能定义详情
      *
      * ***/
    @Override
    public ResponseResult queryThingModelPublished(QueryThingModelPublishedRequest request) {

        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        QueryThingModelPublishedResponse response ;
        try {
            response =   client.queryThingModelPublished(request);
        } catch (Exception e) {
          throw  new RuntimeException("获取功能定义详情失败");
        }


        return ResponseResult.success(response.getBody().getData());
    }
    /**
     * 修改设备信息
     *
     * **/

    @Override
    public Object batchUpdateDevice(DeviceDto dto) {
        //1.通过id查询设备
        Device device = deviceMapper.selectByPrimaryKey(dto.getId());
        //判断数据库中是否有无设备
        if (BeanUtil.isEmpty(device)){
            throw  new RuntimeException("没有该设备");
        }
        //调用物联网接口，更新云服务设备信息
        BatchUpdateDeviceNicknameRequest request = new BatchUpdateDeviceNicknameRequest();
        request.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
        BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo
                nicknameInfo = BeanUtil.toBean(dto, BatchUpdateDeviceNicknameRequest.BatchUpdateDeviceNicknameRequestDeviceNicknameInfo.class);
        request.setDeviceNicknameInfo(Lists.newArrayList(nicknameInfo));
        BatchUpdateDeviceNicknameResponse response ;
        try {
            response = client.batchUpdateDeviceNickname(request);
        } catch (Exception e) {
            throw new RuntimeException("修改失败");
        }
        if (!response.getBody().getSuccess()){
            throw new RuntimeException("修改失败");
        }
        //保存位置
        Device device1 = BeanUtil.toBean(dto, Device.class);
           //判断是不是随身设备
        if (device1.getLocationType().equals(DeviceLocationTypeEnum.PORTABLE_DEVICE.getOrdinal())){
            device1.setPhysicalLocationType(DevicePhysicalLocationTypeEnum.ELDER.getOrdinal());
        }
        //更新数据库数据
        try {
            deviceMapper.updateByPrimaryKeySelective(device1);
        } catch (Exception e) {
          throw  new BaseException(BasicEnum.RE_SELECT_PRODUCT);
        }


        return null;


    }
    /**
     *
     * 删除设备
     *
     * **/

    @Override
    public Object deleteDevice(DeleteDeviceRequest deleteDeviceRequest){
       deleteDeviceRequest.setIotInstanceId(aliIoTConfigProperties.getIotInstanceId());
       DeleteDeviceResponse response;
        try {
            response = client.deleteDevice(deleteDeviceRequest);
        } catch (Exception e) {
            throw new RuntimeException("删除失败");
        }
         if (!response.getBody().getSuccess()){

             return   deviceMapper.deleteByIotId(deleteDeviceRequest.getIotId());

         }
         return new BaseException(BasicEnum.IOT_DELETE_DEVICE_ERROR);
    }




}
